﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.Common;
using System.Data.SqlServerCe;
using System.IO;
using System.Linq;
using System.Text;
using PetaPoco;
/// <summary>
/// Encapsulates the LessFramework database access.
/// Logging, configuration, security....
/// </summary>
public static class Data
{
    /// <summary>
    /// <add key="LessConnectionStringName" value="lessConnection"/>
    /// </summary>
    /// <returns></returns>
    public static string LessConnectionStringName
    {
        get { return Config.GetValue<string>("Data.LessConnectionStringName", "lessConnection", false); }
        set { Config.SetValue("Data.LessConnectionStringName", value, false); }
    }
    
    private static object token = new object();  
    private static Database _database;
    /// <summary>
    /// Main DataBase for LessFramework
    /// </summary>
    public static Database Database
    {
        get
        {
            lock (token)
            {
                if (_database == null)
                {
                    _database = GetDatabase();
                }
                return _database;
            }
        }
        set { _database = value; }
    }
    
    /// <summary>
    /// Gets a new instance of the database manager
    /// </summary>
    /// <returns></returns>
    private static Database GetDatabase()
    {
        Database database = null;
        string lessConnectionStringName = LessConnectionStringName;
        ConnectionStringSettings connectionStringSettings = ConfigurationManager.ConnectionStrings[lessConnectionStringName];
        string connectionString = null;
        if (connectionStringSettings != null)
        {
            connectionString = connectionStringSettings.ConnectionString;
            if(connectionString!=null)
            {
                connectionString = string.Format(connectionString, Config.WorkDirectory);
                VerifyDatabase(connectionString);
                database = new LessDatabase(connectionString, connectionStringSettings.ProviderName);
            }
        }
        return database;
    }
    /// <summary>
    /// Simple factory to create a new database
    /// </summary>
    /// <param name="connectionString"></param>
    private static void VerifyDatabase(string connectionString)
    {
        SqlCeEngine engine = null;
        try
        {
            engine = new SqlCeEngine(connectionString);
            if (!engine.Verify(VerifyOption.Default))
            {
                Log.Warning("DataBase does not exists!!", Log.LogEntry.EntryCategories.DataBase);
                engine.CreateDatabase();
                Log.Info("DataBase created!!", Log.LogEntry.EntryCategories.DataBase);
            }
            else
            {
                Log.Info("DataBase already exists!!", Log.LogEntry.EntryCategories.DataBase);
            }
        }
        catch (Exception e)
        {
            Log.Error(e, Log.LogEntry.EntryCategories.DataBase);
        }
        finally
        {
            if (engine != null) engine.Dispose();
        }
    }
    

    /// <summary>
    /// Derived database to override OnException
    /// Better to use a delegate
    /// </summary>
    public class LessDatabase : Database
    {
        public LessDatabase(IDbConnection connection) : base(connection)
        {
        }

        public LessDatabase(string connectionString, string providerName) : base(connectionString, providerName)
        {
        }

        public LessDatabase(string connectionString, DbProviderFactory provider) : base(connectionString, provider)
        {
        }

        public LessDatabase(string connectionStringName) : base(connectionStringName)
        {
        }

        /// <summary>
        /// A delegate to be used whe something goes wrong with Config
        /// </summary>
        public static Func<Exception, bool> DatabaseLogger;
        /// <summary>
        /// Ads information to the current exception
        /// </summary>
        /// <param name="e"></param>
        public override void OnException(Exception e)
        {
            Exception dbE = new Exception(string.Format("LastCommand:{0}", LastCommand), e);
            //base.OnException(dbE);
            Log.Error(dbE.ToLogString(),Log.LogEntry.EntryCategories.DataBase);
        }
    }
}
